#include <errno.h>
#include <assert.h>
#include <vector>
#include <memory.h>
#include "event_demultiplexer.h"

namespace reactor
{
	EpollDemultiplexer::EpollDemultiplexer()
	{
		m_epoll_fd = ::epoll_create1(EPOLL_CLOEXEC);
		m_cur_evt = 0;
		assert(m_epoll_fd != -1);	
	}

	EpollDemultiplexer::~EpollDemultiplexer()
	{
		::close(m_epoll_fd);
	}

	int EpollDemultiplexer::WaitEvents(
		std::map<handle_t, EventHandlerPtr>* handlers,
		int timeout, time_heap* event_timer)
	{				
		int num = epoll_wait(m_epoll_fd, &_activeEvs[0], kMaxEvents, timeout);
		if (num > 0)
		{
			for (int idx = 0; idx < num; ++idx)
			{
				handle_t handle = _activeEvs[idx].data.fd;
				assert(handlers->find(handle) != handlers->end());

				if ((_activeEvs[idx].events & EPOLLERR) ||
					(_activeEvs[idx].events & EPOLLHUP))
				{
					(*handlers)[handle]->HandleClose();
				}
				else
				{
					if (_activeEvs[idx].events & EPOLLIN)
					{
						(*handlers)[handle]->HandleRead();												
					}
					if (_activeEvs[idx].events & EPOLLOUT)
					{
						(*handlers)[handle]->HandleWrite();									
					}
				}

			}
		}		
		if (event_timer != NULL)
		{			
			event_timer->tick();
		}

		return num;
	}

	int EpollDemultiplexer::RequestEvent(handle_t handle, event_t evt)
	{
		epoll_event ep_evt;
		ep_evt.data.fd = handle;
		ep_evt.events = 0;				
		
		if (evt & kReadEvent)
		{
			ep_evt.events |= EPOLLIN;
		}
		if (evt & kWriteEvent)
		{
			ep_evt.events |= EPOLLOUT;
		}
		
		
		ep_evt.events |= EPOLLONESHOT;

		if (epoll_ctl(m_epoll_fd, EPOLL_CTL_MOD, handle, &ep_evt) != 0)
		{
			if (errno == ENOENT)
			{
				if (epoll_ctl(m_epoll_fd, EPOLL_CTL_ADD, handle, &ep_evt) != 0)
				{
					return -errno;
				}				
			}
			else if (errno == EBADF)
			{
				return -errno;
			}
			
		}		
		return 0;
	}

	int EpollDemultiplexer::UnrequestEvent(handle_t handle)
	{
		epoll_event ep_evt;
		if (epoll_ctl(m_epoll_fd, EPOLL_CTL_DEL, handle, &ep_evt) != 0)
		{
			return -errno;
		}		
		return 0;
	}
} // namespace reactor

